home *** CD-ROM | disk | FTP | other *** search
- # -*- Fundamental -*-
- # http_keepalive.inc
- # (C) Renaud Deraison
- # $Id: http_keepalive.inc,v 1.46 2005/02/19 17:08:36 renaud Exp $
- #
- #
- # The only function which should be used by an external plugin is
- # http_keepalive_send_recv(port, data) which returns the result
- # (or NULL if no connection could be established).
- #
- # Note that the file "http_func.inc" must also be included when
- # using this file.
- #
-
- global_var __ka_socket, __ka_port, __ka_enabled, __ka_last_request;
-
- __ka_socket = 0;
- __ka_port = 0;
- __ka_enabled = -1;
- __ka_last_request = "";
-
-
- #if (isnull(debug_level)) include("global_settings.inc");
-
- #
- # Based on the last headers we received, we determine if we need
- # to close our socket and re-open it or not
- #
- function http_keepalive_check_connection(headers)
- {
- tmp = egrep(pattern:"^Connection: [Cc]lose", string:headers);
- if(tmp)
- {
- http_close_socket(__ka_socket);
- __ka_socket = http_open_socket(__ka_port);
- }
- }
-
- function enable_keepalive(port)
- {
- __ka_enabled = 1;
- __ka_port = port;
- __ka_socket = http_open_socket(port);
- }
- #
- # This function determines if the remote web server is
- # keep-alive-enabled or not.
- #
- function http_keepalive_enabled(port)
- {
- local_var req, soc, r, kb;
-
- kb = get_kb_item(strcat("www/", port, "/keepalive"));
-
- if(kb == "yes"){
- enable_keepalive(port:port);
- return(1);
- }
- else if(kb == "no")return(0);
-
- req = strcat('GET / HTTP/1.1\r\n',
- 'Connection: Keep-Alive\r\n',
- 'Host: ', get_host_name(), '\r\n',
- 'Pragma: no-cache\r\n',
- 'User-Agent: Mozilla/4.75 [en] (X11, U; Nessus)\r\n\r\n');
-
- soc = http_open_socket(port);
- if(!soc)return -2;
- send(socket:soc, data:req);
- r = http_recv(socket:soc);
-
-
- # Apache
- if(egrep(pattern:"^Keep-Alive:.*", string:r))
- {
- http_close_socket(soc);
- set_kb_item(name:strcat('www/', port, '/keepalive'), value:"yes");
- enable_keepalive(port:port);
- return(1);
- }
- else
- {
- # IIS
- send(socket:soc, data:req);
- r = http_recv(socket:soc);
- http_close_socket(soc);
- if(strlen(r)){
- set_kb_item(name:strcat("www/", port, "/keepalive"), value:"yes");
- enable_keepalive(port:port);
- return(1);
- }
- }
-
- set_kb_item(name:strcat("www/", port, "/keepalive"), value:"no");
- return(0);
- }
-
-
- #
- # This function is akin to http_recv_body() except that if the last request
- # was a HEAD, we bail out (whereas http_recv() will timeout).
- #
- function http_keepalive_recv_body(headers, bodyonly)
- {
- local_var body, length, tmp, chunked, killme;
-
- killme = 0;
- length = -1;
-
- if(ereg(pattern:"^HEAD.*HTTP/.*", string:__ka_last_request))
- {
- # HEAD does not return a body
- http_keepalive_check_connection(headers:headers);
- if(bodyonly) return("");
- else return(headers);
- }
-
-
- if("Content-Length" >< headers)
- {
- tmp = egrep(string:headers, pattern:"^Content-Length: *[0-9]+");
- if ( tmp ) length = int(ereg_replace(string:tmp, pattern:"^Content-Length: *([0-9]*)", replace:"\1"));
- }
-
-
-
- if((length < 0) && (egrep(pattern:"transfer-encoding: chunked", string:headers, icase:TRUE)))
- {
- while(1)
- {
- tmp = recv_line(socket:__ka_socket, length:4096);
- length = hex2dec(xvalue:tmp);
- if(length > 1048576)
- {
- length = 1048576;
- killme = 1;
- }
- body = strcat(body, recv(socket:__ka_socket, length:length+2, min:length+2));
- if (strlen(body) > 1048576) killme = 1;
-
- if(length == 0 || killme){
- http_keepalive_check_connection(headers:headers);
- # This is expected - don't put this line before the previous
- if(bodyonly) return(body);
- else return(strcat(headers, '\r\n', body));
- }
- }
- }
-
-
- if(length >= 0)
- {
- # Don't receive more than 1 MB
- if (length > 1048576) length = 1048576;
-
- body = recv(socket:__ka_socket, length:length, min:length);
- }
- else {
- # If we don't have the length, we close the connection to make sure
- # the next request won't mix up the replies.
-
- #display("ERROR - Keep Alive, but no length!!!\n", __ka_last_request);
- body = recv(socket:__ka_socket, length:16384);
- if (body =~ '<html>' && body !~ '</html>') # case insensitive
- {
- repeat
- {
- tmp = recv(socket:__ka_socket, length:16384);
- body += tmp;
- }
- until (! tmp || body =~ "</html>");
- if (debug_level && body !~ "</html>") display("http_keepalive_recv_body: incomplete body?\n------------\n", body, "\n------------\n");
- }
- http_close_socket(__ka_socket);
- __ka_socket = http_open_socket(__ka_port);
- }
-
-
- http_keepalive_check_connection(headers:headers);
- if(bodyonly) return(body);
- else return(strcat(headers, '\r\n', body));
- }
-
-
- #----------------------------------------------------------------------#
-
- # We close our socket on exit.
- function on_exit()
- {
- if(__ka_socket)
- {
- http_close_socket(__ka_socket);
- }
- }
-
-
-
- #----------------------------------------------------------------------#
-
-
- #
- # This is our "public" Keep-Alive function. It sends <data> to the remote
- # host on port <port>, and returns the result, or NULL if no connection
- # could be established.
- #
- function http_keepalive_send_recv(port, data, bodyonly)
- {
- local_var id, n, ret, headers;
-
- if (debug_level > 1)
- display("http_keepalive_send_recv(port: ", port, ", data: ", data, ", bodyonly: ", bodyonly, ")\n");
-
- if ( ! data ) { display("http_keepalive_send_recv(): NULL data!\n"); return NULL; }
-
- if(__ka_enabled == -1) __ka_enabled = http_keepalive_enabled(port:port);
- if(__ka_enabled == -2) return NULL;
-
-
- if(__ka_enabled == 0)
- {
- local_var soc, r, body;
- soc = http_open_socket(port);
- if(!soc)return NULL;
- if (send(socket:soc, data:data) <= 0)
- {
- http_close_socket(soc);
- return NULL;
- }
- headers = http_recv_headers(soc);
- if(headers) body = http_recv_body(socket:soc, headers:headers, length:0);
- http_close_socket(soc);
- if(bodyonly) return(body);
- else return(strcat(headers, '\r\n', body));
- }
-
-
- if((port != __ka_port)||(!__ka_socket))
- {
- if(__ka_socket)http_close_socket(__ka_socket);
- __ka_port = port;
- __ka_socket = http_open_socket(port);
- if(!__ka_socket)return NULL;
- }
-
- id = stridx(data, '\r\n\r\n');
- data = str_replace(string:data, find:"Connection: Close", replace:"Connection: Keep-Alive", count:1);
- __ka_last_request = data;
- n = send(socket:__ka_socket, data:data);
- if (n >= strlen(data))
- headers = http_recv_headers(__ka_socket);
- if (! headers)
- {
- http_close_socket(__ka_socket);
- __ka_socket = http_open_socket(__ka_port);
- if(__ka_socket == 0)return NULL;
- if (send(socket:__ka_socket, data:data) < strlen(data))
- {
- http_close_socket(__ka_socket);
- __ka_socket = NULL;
- return NULL;
- }
- headers = http_recv_headers(__ka_socket);
- }
-
- return http_keepalive_recv_body(headers: headers, bodyonly:bodyonly);
- }
-
-
-
- #
- # Same as check_win_dir_trav(), but with KA support
- #
- function check_win_dir_trav_ka(port, url, quickcheck)
- {
- local_var soc, req, cod, buf;
- #display("check_win_dir_trav(port=", port, ", url=", url, ", quickcheck=", quickcheck, ")\n");
-
-
- req = http_get(item:url, port:port);
- buf = http_keepalive_send_recv(port:port, data:req);
-
- # if (quickcheck)
- # {
- # if (ereg(pattern:"^HTTP/.* 200 ", string:buf)) return (1);
- # return (0);
- # }
-
- if ( ("ECHO" >< buf) || ("RESET" >!< buf && ("SET " >< buf)) ||
- ("export" >< buf) || ("EXPORT" >< buf) ||
- ("doskey" >< buf) || ("DOSKEY" >< buf) ||
- ("[boot loader]" >< buf) || ("[fonts]" >< buf) ||
- ("[extensions]" >< buf) || ("[mci extensions]" >< buf) ||
- ("[files]" >< buf) || ("[Mail]" >< buf) ||
- ("[operating systems]" >< buf) )
- {
- return(1);
- }
- return(0);
- }
-
- #
- #
- #
- function is_cgi_installed_ka(item, port)
- {
- local_var r, no404, dir, slash, dirs, banner;
-
-
- #
- # Some embedded web servers can not have arbitrary CGIs
- #
- banner = get_http_banner(port:port);
- if ( egrep(pattern:"^Server: (CUPS|MiniServ|AppleShareIP|Embedded HTTPD|IP_SHARER|Ipswitch-IMail|MACOS_Personal_Websharing|NetCache appliance|ZyXEL-RomPager|cisco-IOS|u-Server)", string:banner ) )
- return NULL;
-
- if(item[0] != "/")
- {
- dirs = cgi_dirs();
- slash = "/";
- }
- else
- {
- dirs = make_list("");
- slash = "";
- }
-
- no404 = get_kb_item(strcat("www/no404/", port));
-
- foreach dir (dirs)
- {
- r = http_keepalive_send_recv(port:port, data:http_get(item:dir + slash + item, port:port));
- if( r == NULL ) return NULL;
-
- if(r =~ "^HTTP/1\.[0-9.] +200 +")
- {
- if(no404 && tolower(no404) >< tolower(r)) return 0;
- if (debug_level > 1) display("is_cgi_installed_ka(item: ", item, ", port:", port, ")\n------------\n", r, "\n------------\n");
- return(1);
- }
- }
- return(0);
- }
-
- #
-
- function get_http_page(port, url, redirect)
- {
- local_var r, u, v, i, l, seen_loc, n;
-
- if (isnull(redirect))
- n = 32;
- else if (redirect <= 0)
- n = 1;
- else
- n = redirect + 1;
-
- seen_loc = make_list();
- u = url;
- for (i = 0; i < n; i ++) # Limited iterations to avoid traps
- {
- seen_loc[u] = 1;
- r = http_keepalive_send_recv(port: port,
- data: http_get(port: port, item: u));
- if (isnull(r)) return NULL;
-
- if (r =~ "^HTTP/1\.[01] +30[0-9] .*")
- {
- v = eregmatch(pattern: "\r\nLocation: *([^ \t\r\n]+)[ \t]*[\r\n]+",
- string: r, icase: 1);
- if (isnull(v)) return NULL; # Big problem
- l = v[1];
- if (seen_loc[l]) return NULL;
- seen_loc[l] = 1;
- }
- else if (r =~ "^HTTP/1\.[01] +200 ")
- {
- r = strstr(r, '\r\n\r\n');
- r = substr(r, 4);
- return r;
- }
- else # Code 4xx or 5xx
- return NULL;
- }
- # Loop?
- return NULL;
- }
-